#include "WinThread.h"
#include "process.h"

bool Win32UpdateCell::OnUpdate(double NowTime,double PastTime)
{
	return true;
}

bool Win32RenderCell::OnWork()
{
	return true;
}

WinThreadWorker::WinThreadWorker()
{
}

WinThreadWorker::~WinThreadWorker()
{
}

bool WinThreadWorker::Init()
{
	
	m_ThreadWorkBenginEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
	m_ThreadWorkFinshedEvent = CreateEvent( NULL, FALSE, FALSE, NULL );
	m_ThreadWorkSemaphore = CreateSemaphore(NULL,0,MAX_SIGNAL_COUNT,NULL);
	m_Identifier = ( HANDLE )_beginthreadex( 
			NULL, 
			0, 
			WinThreadProc, 
			this, 
			CREATE_SUSPENDED, 
			NULL );
	if(m_Identifier == NULL)
	{
		return false;
	}
	if(OnInit())
	{
			
		return true;
	}
	else
		return false;
	return true;

}

//void ThreadWorker::ThreadWorkerRun()
//{
//	ResumeThread(m_Identifier);
//}

bool WinThreadWorker::StartWork()
{
	ResumeThread(m_Identifier);
	return true;
}

bool WinThreadWorker::StopWork()
{
	return true;
}

bool WinThreadWorker::KillMyself()
{
	return true;
}

bool WinThreadWorker::OnInit(void* pParemeter)
{
	return true;
}

bool WinThreadWorker::OnWork()
{
	return true;
}

bool WinThreadWorker::OnWorkFinished()
{
	return true;
}

void WinThreadWorker::OnThreadEvent()
{
	
}

void WinThreadWorker::OnThreadState()
{

}

void WinThreadWorker::AddSignalEvent(ThreadEvent* pEvent)
{
	m_ThreadWorkerEventVector.push_back(pEvent);
	ReleaseSemaphore( this->m_ThreadWorkSemaphore, 1, NULL );
}


//--------------------------------------------------------------------------------------
// Helper functions for querying information about the processors in the current
// system.  ( Copied from the doc page for GetLogicalProcessorInformation() )
//--------------------------------------------------------------------------------------
typedef BOOL (WINAPI *LPFN_GLPI)(
    PSYSTEM_LOGICAL_PROCESSOR_INFORMATION, 
    PDWORD);


//  Helper function to count bits in the processor mask
static DWORD CountBits(ULONG_PTR bitMask)
{
    DWORD LSHIFT = sizeof(ULONG_PTR)*8 - 1;
    DWORD bitSetCount = 0;
    DWORD bitTest = 1 << LSHIFT;
    DWORD i;

    for( i = 0; i <= LSHIFT; ++i)
    {
        bitSetCount += ((bitMask & bitTest)?1:0);
        bitTest/=2;
    }

    return bitSetCount;
}

int WinThreadControler::GetSuitableThreadCounts()
{
	DWORD procCoreCount = 0;    // Return 0 on any failure.  That'll show them.

    LPFN_GLPI Glpi;

    Glpi = (LPFN_GLPI) GetProcAddress(
        GetModuleHandle(TEXT("kernel32")),
        "GetLogicalProcessorInformation");
    if (NULL == Glpi) 
    {
        // GetLogicalProcessorInformation is not supported
        return procCoreCount;
    }

    BOOL done = FALSE;
    PSYSTEM_LOGICAL_PROCESSOR_INFORMATION buffer = NULL;
    DWORD returnLength = 0;

    while (!done) 
    {
        DWORD rc = Glpi(buffer, &returnLength);

        if (FALSE == rc) 
        {
            if (GetLastError() == ERROR_INSUFFICIENT_BUFFER) 
            {
                if (buffer) 
                    free(buffer);

                buffer=(PSYSTEM_LOGICAL_PROCESSOR_INFORMATION)malloc(
                    returnLength);

                if (NULL == buffer) 
                {
                    // Allocation failure\n
                    return procCoreCount;
                }
            } 
            else 
            {
                // Unanticipated error
                return procCoreCount;
            }
        } 
        else done = TRUE;
    }

    DWORD byteOffset = 0;
    PSYSTEM_LOGICAL_PROCESSOR_INFORMATION ptr = buffer;
    while (byteOffset < returnLength) 
    {
        if (ptr->Relationship == RelationProcessorCore) 
        {
            if(ptr->ProcessorCore.Flags)
            {
                //  Hyperthreading or SMT is enabled.
                //  Logical processors are on the same core.
                procCoreCount += 1;
            }
            else
            {
                //  Logical processors are on different cores.
                procCoreCount += CountBits(ptr->ProcessorMask);
            }
        }
        byteOffset += sizeof(SYSTEM_LOGICAL_PROCESSOR_INFORMATION);
        ptr++;
    }

    free (buffer);

    return procCoreCount;
}


bool WinThreadControler::CreateSuitableThreadModle()
{
	int cpus = GetSuitableThreadCounts();
	int suitable_threads = 6;
	m_SuitableThreadCounts = suitable_threads;
	//m_ThreadControlObject = new HANDLE[m_SuitableThreadCounts];
	//memset(m_ThreadControlObject,0,m_SuitableThreadCounts);
	return true;
}

unsigned int WINAPI WinThreadProc( LPVOID lpParameter )
{

	return 0;
}

bool WinThreadControler::Initialize()
{
	int cpus = GetSuitableThreadCounts();
	int suitable_threads = cpus;
	m_SuitableThreadCounts = cpus;
	m_ThreadControlObject = new HANDLE[m_SuitableThreadCounts];
	memset(m_ThreadControlObject,0,m_SuitableThreadCounts);
	for(int i = 0; i<suitable_threads; i++)
	{
		ThreadWorker* thread = new WinThreadWorker();
		MarkThreadControlObject(i,thread->m_ThreadWorkFinshedEvent);
		m_ThreadWorkerMap[thread->m_ThreadName] = thread;
	}
	return true;
}

bool WinThreadControler::InitThread(ThreadWorker* thread)
{
	if(m_ThreadWorkerMap.size() <= m_SuitableThreadCounts)
		if(thread)
		{
			int free_index = GetFreeThreadControlObjectIndex();
			if(free_index == -1)
				return false;
			MarkThreadControlObject(free_index,thread->m_ThreadWorkFinshedEvent);
			m_ThreadWorkerMap[thread->m_ThreadName] = thread;
			return true;
		}
	return false;
}

bool WinThreadControler::Work()
{
	return true;
}

void WinThreadControler::CheckSynFinish()
{

}